// Copyright (c) 2023 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Basic example of actor.

use ylong_light_actor::event_handler::{Handler, Priority, ToActor, ToActorExt};
use ylong_light_actor::Dispatcher;

// Defines user struct.
struct BankAccount {
    account_number: u32,
    balance: f64,
}

// Makes user struct as `Actor`
impl ToActor for BankAccount {}

//Defines msg struct
struct Deposit {
    amount: f64,
}

impl Handler<Deposit> for BankAccount {
    type ReturnType = f64;

    fn handle(&mut self, msg: Deposit) -> Self::ReturnType {
        self.balance += msg.amount;
        println!(
            "account: {}, balance: {}",
            self.account_number, self.balance
        );
        self.balance
    }
}

#[tokio::main]
async fn main() {
    // 1. Starts a dispatcher, and gets a handle to it.
    let dispatcher = Dispatcher::new().unwrap();
    let handle = dispatcher.handle();

    // 2. Starts a new thread, and runs the dispatcher on the thread. The thread will run forever
    // until handle.stop() be called.
    let join = std::thread::spawn(move || dispatcher.run());

    // 3. Starts an actor on the dispatcher, and sends msgs to the actor.
    let actor = BankAccount {
        account_number: 1234,
        balance: 1000.0,
    }
    .start_actor_on(&handle);

    actor
        .send_msg(Deposit { amount: 90.0 }, "handler_task", 50, Priority::Low)
        .unwrap();
    actor
        .send_task(|_| println!("hello"), "hello_task", 300, Priority::Low)
        .unwrap();
    actor
        .send_sync_msg(Deposit { amount: 10.0 }, "handler_task", 50, Priority::Low)
        .await
        .unwrap();
    actor
        .send_sync_task(|_| println!("world"), "world_task", 400, Priority::Low)
        .await
        .unwrap();

    // 4. Stops the dispatcher, and the thread will then exit.
    handle.stop();
    join.join().unwrap();
}
